# -*- coding: utf-8 -*-
#
# Copyright (c) 2010-2011, Monash e-Research Centre
#   (Monash University, Australia)
# Copyright (c) 2010-2011, VeRSI Consortium
#   (Victorian eResearch Strategic Initiative, Australia)
# Copyright (c) 2011,2012 RMIT e-Research Office
#   (RMIT University, Australia)
# All rights reserved.
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
#    *  Redistributions of source code must retain the above copyright
#       notice, this list of conditions and the following disclaimer.
#    *  Redistributions in binary form must reproduce the above copyright
#       notice, this list of conditions and the following disclaimer in the
#       documentation and/or other materials provided with the distribution.
#    *  Neither the name of RMIT University, Monash University, 
#       the VeRSI, the VeRSI Consortium members, nor the
#       names of its contributors may be used to endorse or promote products
#       derived from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
"""
.. module:: rif_cs_PublishProvider    
   :synopsis: Provider of rif-cs publication to ANDS

.. moduleauthor:: Ian Thomas <Ian.Edward.Thomas@rmit.edu.au>


"""

import os
import logging

from django.forms.formsets import formset_factory
from django.core.urlresolvers import reverse
from django.contrib import messages
from django.conf import settings

from smra.smra_portal.publish.interfaces import PublishProvider
from smra.smra_portal.models import VirtualCollection
from smra.smra_portal.models import VirtualCollectionParameterSet
from smra.smra_portal.models import VirtualCollectionParameter
from smra.smra_portal.models import Schema
from smra.smra_portal.models import ParameterName
from smra.smra_portal.forms import CollectionPartyRelation

logger = logging.getLogger(__name__)

class rif_cs_PublishProvider(PublishProvider):

    def __init__(self, virt):
        self.virt = virt

    name = u'myANDS'

    def execute_publish(self, request):
        """
        Attach the user-selected RIF-CS profile name to the experiment
        as a parameter

        :param request: a HTTP Request instance
        :type request: :class:`django.http.HttpRequest`

        """
        logger.debug("execute_publish %s %s" % (self.name,request))
        Party_Formset = formset_factory(CollectionPartyRelation,extra=2)        
        party_formset = Party_Formset(request.POST)
        logger.debug("partyloaded")
        logger.debug(party_formset.is_valid())       
        logger.debug(party_formset.errors)
        logger.debug(party_formset.cleaned_data)
        if party_formset.is_valid():
            self._del_party_paramsets()
            for form in party_formset:
                data = form.cleaned_data
                if 'party' in data:
                    party = data['party']
                else:
                    party = None       
                if 'relation' in data:
                    relation_name = data['relation']
                else:
                    relation_name = None         
                logger.debug("%s %s" % (party, relation_name))
                logger.debug("virt=%s" % self.virt)
                if party and relation_name:
                    self._save_party_refs(party, relation_name)
        else:
            messages.error(request,"Invalid party form entry")     
        virt = VirtualCollection.objects.get(pk=self.virt.pk)
        # mint handle for RIFCS key
        if settings.KEY_HANDLE_ENABLE:
            logger.debug("generating handles")
            if not virt.key:
                logger.debug("not set")
                try:
                    from HandleService import HandleService
                    hdlsrv = HandleService()
                    response = hdlsrv.mint(
                            settings.AUTHTYPE, settings.IDENTIFIER,
                            settings.AUTHDOMAIN, settings.APPID,
                            settings.MINTURL, 
                            reverse('virtmeta',args=[virt.pk]))
                    from xml.dom import minidom
                    xmldoc = minidom.parseString(response)
                    logger.debug("xmldoc=%s" % xmldoc)
                    handle = xmldoc.firstChild.childNodes[1].attributes["handle"].value
                    logger.debug("handle=%s" % handle)
                    if handle:
                        virt.key = handle
                        virt.save()
                except KeyError:
                    logger.error(response)
                    logger.error("Persistent handle minting failed")
            else:
                logger.debug("existing key = %s" % virt.key)
        if request.POST['profile']: 
            profile = request.POST['profile']
            self.save_rif_cs_profile(virt, profile)
            return {'status': True,
            'message': 'Success'}
        else:
            return {'status': True,
            'message': 'No profiles exist to choose from'}



    def _del_party_paramsets(self):
        """ Remove existing party associations
        """
        namespace = settings.RIFCS_PARTY_SCHEMA
        try:
            schema = Schema.objects.get(
                namespace__exact=namespace)
        except Schema.DoesNotExist:
            return 
        parameterset = None
        try:
            parameterset = \
                         VirtualCollectionParameterSet.objects.filter(\
                                schema=schema,
                                virt=self.virt)
        except VirtualCollectionParameterSet.DoesNotExist, e:
            return
        
        
        parameterset.delete()
        
    def get_context(self, request):
        """
        Display a list of profiles on screen for selection

        :param request: a HTTP Request instance
        :type request: :class:`django.http.HttpRequest`

        """

        rif_cs_profiles = self.get_rif_cs_profile_list()

        selected_profile = "default.xml"

        if self.get_profile():
            selected_profile = self.get_profile()
            
        Party_Formset = formset_factory(CollectionPartyRelation,extra=2)
        party_formset = Party_Formset()

        return {"rif_cs_profiles": rif_cs_profiles,
                "selected_profile": selected_profile,
                "party_formset":party_formset}

    def get_path(self):
        """
        Return the relative template file path to display on screen

        :rtype: string
        """
        return "rif_cs_profile/form.html"

    def get_rif_cs_profile_list(self):
        """
        Return a list of the possible RIF-CS profiles that can
        be applied. Scans the profile directory.

        :rtype: list of strings
        """

        SMRA_ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__)))
        profile_dir = os.path.join(SMRA_ROOT,
                      "profiles/")

        logger.debug("profile_dir = %s" % profile_dir)
        profile_list = list()

        try:
            for f in os.listdir(profile_dir):
                if not os.path.isfile(profile_dir + f) or \
                       f.startswith('.') or not f.endswith('.xml'):
                    continue
                profile_list.append(f)
        except OSError:
            logger.error("Can't find profile directory " +
            "or no profiles available")

        return profile_list
    
    def _make_param(self,schema,name):
        try:
            param = ParameterName.objects.get(
                schema__namespace__exact=schema.namespace,
                name=name)
        except ParameterName.DoesNotExist:
            logger.debug("%s does not exist. Creating." % name)
            param = ParameterName(name=name,schema=schema)
            param.save()
        return param
    

    def _save_party_refs(self,  party, party_relation):
        namespace = settings.RIFCS_PARTY_SCHEMA
    
        
        logger.debug("saving party")
        schema = None
        try:
            schema = Schema.objects.get(
                namespace__exact=namespace)
        except Schema.DoesNotExist:
            logger.debug('Schema ' + namespace +
            ' does not exist. Creating.')
            schema = Schema(namespace=namespace)
            schema.save()
            
        virt = VirtualCollection.objects.get(pk=self.virt.pk)
            
        party_id_param = self._make_param(schema, "party_id")
        relation_param = self._make_param(schema, "relationtocollection_id")                    
   
        parameterset = VirtualCollectionParameterSet(\
                                schema=schema,
                                virt=virt)
        parameterset.save()    
        ep = VirtualCollectionParameter.objects.filter(name=party_id_param,
            paramset=parameterset,
            paramset__virt__id=virt.pk)
        for p in ep:
            p.delete()
        ep = VirtualCollectionParameter(
            paramset=parameterset,
            name=party_id_param,
            value=party.pk)
        ep.save()                        
        ep = VirtualCollectionParameter.objects.filter(name=relation_param,
            paramset=parameterset,
            paramset__virt__id=virt.pk)
        for p in ep:
            p.delete()
        ep = VirtualCollectionParameter(
            paramset=parameterset,
            name=relation_param,
            value=party_relation)
        ep.save()
   
    def save_rif_cs_profile(self, virt, profile):
        """
        Save selected profile choice as experiment parameter
        """
        namespace = "http://rmit.edu.au/smra/rif-cs/profile/"
        
        logger.debug("saving rifcs")
        schema = None
        try:
            schema = Schema.objects.get(
                namespace__exact=namespace)
        except Schema.DoesNotExist:
            logger.debug('Schema ' + namespace +
            ' does not exist. Creating.')
            schema = Schema(namespace=namespace)
            schema.save()
        try:
            parametername = ParameterName.objects.get(
            schema__namespace__exact=schema.namespace,
            name="profile")
        except ParameterName.DoesNotExist:
            logger.debug("profile does not exist. Creating.")
            parametername = ParameterName(name="profile",schema=schema)
            parametername.save()
        parameterset = None
        try:
            parameterset = \
                         VirtualCollectionParameterSet.objects.get(\
                                schema=schema,
                                virt=virt)
        except VirtualCollectionParameterSet.DoesNotExist, e:
            parameterset = VirtualCollectionParameterSet(\
                                schema=schema,
                                virt=virt)

            parameterset.save()
            logger.debug("paramerset=%s" % parameterset)
        # if a profile param already exists
        if self.get_profile():
            ep = VirtualCollectionParameter.objects.filter(name=parametername,
            paramset=parameterset,
            paramset__virt=self.virt)
            for p in ep:
                p.delete()
        ep = VirtualCollectionParameter(
            paramset=parameterset,
            name=parametername,
            value=profile)
        ep.save()

    def get_profile(self):
        """
        Retrieve existing rif-cs profile for experiment, if any
        """

        ep = VirtualCollectionParameter.objects.filter(name__name='profile',
        paramset__schema__namespace='http://rmit.edu.au/smra/rif-cs/profile/',
        paramset__virt=self.virt)

        if len(ep):
            return ep[0].value
        else:
            return None
